package com.nantian.office.excel;

import com.nantian.annotation.Cell;
import com.nantian.annotation.DateFormat;
import com.nantian.annotation.Regular;
import com.nantian.annotation.Sheet;
import com.nantian.common.util.ClassUtils;
import com.nantian.common.util.StringUtils;
import com.nantian.exception.ExcelException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>ClassName: BeanUtils</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright©2014</p>
 * <p>Company: 广州南天电脑系统有限公司</p>
 * <p>Date: 2020-01-19</p>
 *
 * @author 刘晓辉
 * @version 1.0
 */
public class BeanUtils {
    private static Logger log = LoggerFactory.getLogger(BeanUtils.class);
    private static final String IS = "is";
    private static final String ISIS = "isis";
    private static final String DECIMAL_POINT = ".";

    /**
     * 解析bean的属性字段
     * 获取cell的配置
     * @param javaBean bean
     * @param <T> bean类型
     * @return 符合条件的field字段集合
     */
    public static <T>List<FieldProperty> parsingField(Class<T> javaBean) {
        List<FieldProperty> fieldProperties = new ArrayList<>(16);
        Field[] fields = javaBean.getDeclaredFields();
        for (Field field : fields) {
            boolean staticField = Modifier.isStatic(field.getModifiers());
            boolean finalField = Modifier.isFinal(field.getModifiers());
            //非静态字段，且不是final修饰
            if (!staticField && !finalField) {
                FieldProperty fieldProperty = new FieldProperty();
                Object cellObj = field.getAnnotation(Cell.class);
                //如果没有使用cell的注解，则不解析该字段
                if (cellObj == null) {
                    continue;
                }
                Cell cell = (Cell) cellObj;
                fieldProperty.setEmpty(cell.empty());
                fieldProperty.setIndex(cell.index());
                fieldProperty.setFieldName(field.getName());
                fieldProperty.setHeight(cell.height());
                fieldProperty.setWidth(cell.width());
                fieldProperty.setTitle(cell.title());
                fieldProperty.setFieldType(field.getType());
                //是否有使用Regular注解
                Object regularObj = field.getAnnotation(Regular.class);
                if (regularObj != null) {
                    Regular regular = (Regular) regularObj;
                    fieldProperty.setRegular(regular.regular());
                }
                //是否有使用DateFormat注解
                Object dateFormate = field.getAnnotation(DateFormat.class);
                if (dateFormate != null) {
                    DateFormat df = (DateFormat) dateFormate;
                    fieldProperty.setDateFormate(df.formate());
                }
                String fieldGetMethodName = getFieldGetMethod(field.getType(), field.getName());
                String fieldSetMethodName = getFieldSetMethod(field.getType(), field.getName());

                fieldProperty.setFieldGetMethod(fieldGetMethodName);
                fieldProperty.setFieldSetMethod(fieldSetMethodName);
                fieldProperties.add(fieldProperty);
            }
        }
        return fieldProperties;
    }

    /**
     * 获取sheet名称
     * @param obj bean
     * @return sheet名称
     */
    public static String getSheetName(Class<?> obj) {
        Object sheetObj = obj.getAnnotation(Sheet.class);
        if (sheetObj != null) {
            Sheet sheet = (Sheet) sheetObj;
            return sheet.name();
        } else {
            return "";
        }
    }

    public static Object getMethodValue (Object obj, FieldProperty fieldProperty) {
        Class objClass = obj.getClass();
        Method method = null;
        try {
            method = objClass.getMethod(fieldProperty.getFieldGetMethod());
        } catch (NoSuchMethodException e) {
            log.error(e.getMessage(), e);
            throw new ExcelException("找不到" + fieldProperty.getFieldGetMethod() + "的属性方法");
        }
        try {
            Object value = method.invoke(obj);
            if (value != null) {
                //日期类型
                if (ClassUtils.isDate(fieldProperty.getFieldType().getName())) {
                    //看是否有指定日期类型格式
                    String formate = fieldProperty.getDateFormate();
                    if (StringUtils.isBlank(formate)) {
                        //没有指定格式则按默认格式
                        formate = "yyyy-MM-dd HH:mm:ss";
                    }
                    SimpleDateFormat dateFormat = new SimpleDateFormat(formate);
                    //将date类型转成指定格式的时间
                    String datetime = dateFormat.format(value);
                    value = datetime;
                }
                //将所有的值都转成字符串
                value = String.valueOf(value);
            }
            return value;
        } catch (IllegalAccessException e) {
            throw new ExcelException("获取" + fieldProperty.getFieldGetMethod() + "的属性方法失败");
        } catch (InvocationTargetException e) {
            throw new ExcelException("获取" + fieldProperty.getFieldGetMethod() + "的属性方法失败");
        }
    }

    /**
     * 获取属性的get方法
     * @param fieldType field类型
     * @param fieldName field名称
     * @return field的get方法
     */
    public static String getFieldGetMethod(Class<?> fieldType, String fieldName) {
        String method = null;
        Boolean isBooleanType = ClassUtils.isBoolean(fieldType.getName());
        String prefix = "get";
        int length = fieldName.length();
        if (isBooleanType) {
            prefix = "is";
            if (!fieldName.startsWith(ISIS)) {
                if (fieldName.startsWith(IS)) {
                    //截取第三个字符
                    String str = fieldName.substring(2, 3);
                    //如果第三个字符是大写的，才符合命名规范
                    if (str.toUpperCase().equals(str)) {
                        fieldName = fieldName.substring(2, length);
                    }
                }
            }
        }
        return getFieldMethod(prefix, fieldName);
    }

    /**
     * 获取属性的set方法
     * @param fieldType field类型
     * @param fieldName field名称
     * @return field的set方法
     */
    public static String getFieldSetMethod(Class<?> fieldType, String fieldName) {
        String method = null;
        Boolean isBooleanType = ClassUtils.isBoolean(fieldType.getName());
        String prefix = "set";
        int length = fieldName.length();
        if (isBooleanType && !fieldName.startsWith(ISIS)) {
            if (fieldName.startsWith(IS)) {
                //截取第三个字符
                String str = fieldName.substring(2, 3);
                //如果第三个字符是大写的，才符合命名规范
                if (str.toUpperCase().equals(str)) {
                    fieldName = fieldName.substring(2, length);
                }
            }
        }
        return getFieldMethod(prefix, fieldName);
    }

    /**
     * 获取field方法名
     * @param prefix 前缀
     * @param fieldName 方法名
     * @return field方法名
     */
    public static String getFieldMethod(String prefix, String fieldName) {
        String method = null;
        int length = fieldName.length();
        if (fieldName.length() == 1) {
            method = prefix + fieldName.toUpperCase();
        } else {
            method = prefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, length);
        }
        return method;
    }

    /**
     * 根据不同的类型，转换值
     * @param fieldProperty 字段属性
     * @param value 值
     * @return 转换类型后的值
     */
    public static Object conversionType(FieldProperty fieldProperty, Object value) {
        String type = fieldProperty.fieldType.getName();
        if (ClassUtils.isBoolean(type)) {
            if (value == null || "".equals(value)) {
                return Boolean.valueOf(false);
            }
            return Boolean.valueOf(value.toString());
        } else if (ClassUtils.isByte(type)) {
            if (value == null || "".equals(value)) {
                return Byte.valueOf("0");
            }
            return Byte.valueOf(value.toString());
        } else if (ClassUtils.isShort(type)) {
            if (value == null || "".equals(value)) {
                return Short.valueOf("0");
            }
            return Short.valueOf(value.toString());
        } else if (ClassUtils.isIntOrInteger(type)) {
            if (value == null || "".equals(value)) {
                return Integer.valueOf(0);
            }
            String v = value.toString();
            if (v.indexOf(DECIMAL_POINT) != -1) {
                v = v.split("\\.")[0];
            }
            return Integer.valueOf(v);
        } else if (ClassUtils.isLong(type)) {
            if (value == null || "".equals(value)) {
                return Long.valueOf(0L);
            }
            return Long.valueOf(value.toString());
        } else if (ClassUtils.isFloat(type)) {
            if (value == null || "".equals(value)) {
                return new Float(0.0f);
            }
            return Float.valueOf(value.toString());
        } else if (ClassUtils.isDouble(type)) {
            if (value == null || "".equals(value)) {
                return new Double(0.0d);
            }
            return Double.valueOf(value.toString());
        } else if (ClassUtils.isStringType(type)) {
            if (value == null || "".equals(value)) {
                return value;
            }
            return String.valueOf(value);
        } else if (ClassUtils.isDate(type)) {
            if (value == null || "".equals(value)) {
                return null;
            }
            String format = fieldProperty.getDateFormate();
            if (StringUtils.isBlank(format)) {
                format = "yyyy-MM-dd HH:mm:ss";
            }
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            Date date = null;
            try {
                date = dateFormat.parse(String.valueOf(value));
            } catch (ParseException e) {
                throw new IllegalArgumentException("【" + value + "】转换成date类型失败");
            }
            return date;
        }
        return null;
    }


    public static void main(String[] args) {
        fieldMethodOut("isTest");
        fieldMethodOut("Test");
        fieldMethodOut("bool");
        fieldMethodOut("isisTest");
        fieldMethodOut("ISTest");
        fieldMethodOut("IsisTest");
        fieldMethodOut("b");
    }

    public static void fieldMethodOut(String fieldName) {
        String method = getFieldGetMethod(String.class, fieldName);
        System.out.println(fieldName + " get method:" + method);

        String setmethod = getFieldSetMethod(String.class, fieldName);
        System.out.println(fieldName + " set method:" + setmethod);
    }
}
